package snucse.teamd;

import java.util.List;
import java.util.Vector;

import javax.media.opengl.GL2;

import snucse.teamd.math.Edge;
import snucse.teamd.math.MyMath;
import snucse.teamd.math.Projection;
import snucse.teamd.math.Vec2;

public class Collide {

	public static Arbiter arb;
	
	private static boolean sat(Vector<Vec2> vList1, Vector<Vec2> vList2, Body b1, Body b2){
		Contact contact;
		Vec2 v1, v2;
		Edge sepAxis, sepPlane, e1, e2;//, prjE1, prjE2;
		Vec2 sepAxisProject;
		Projection p1, p2;
		Vec2 collisionVec2=new Vec2(9999f, 9999f);
		Edge colSepAxis = new Edge(new Vec2(), new Vec2());
		double minOverlap=9999f, tempLength;
		int incidentBody=2;//1=b1, 2=b2
		//System.out.println("-----------------------------------------------------------");
	//	boolean isOverlaped;
		
		/*for (int i=0; i<vList1.size();i++){
			System.out.print("vlist1 v=");
			vList1.get(i).print();
		}
		for (int i=0; i<vList2.size();i++){
			System.out.print("vlist2 v=");
			vList2.get(i).print();
		}*/
		
		for (int i=0;i<vList1.size()+vList2.size();i++){
			v1= (i<vList1.size()
					? MyMath.rotation(vList1.get(i), b1.centerOfMass, b1.rotAngle)
					: MyMath.rotation(vList2.get(i-vList1.size()), b2.centerOfMass, b2.rotAngle));
			v2= (i<vList1.size()
					? MyMath.rotation(vList1.get((i+1)%vList1.size()), b1.centerOfMass, b1.rotAngle)
					: MyMath.rotation(vList2.get((i+1-vList1.size())%vList2.size()), b2.centerOfMass, b2.rotAngle));
	//		isOverlaped=true;
			sepAxis = new Edge(v1, v2); 
					/*(i<vList1.size() 
					? new Edge(vList1.get(i), vList1.get((i+1)%vList1.size()))
					: new Edge(vList2.get(i-vList1.size()), vList2.get((i+1-vList1.size())%vList2.size())));*/
			double temp_x = (v2.getY() - v1.getY())/(Vec2.distance(v1, v2));
			double temp_y = -(v2.getX() - v1.getX())/(Vec2.distance(v1, v2));
			
			sepPlane=new Edge(new Vec2(0,0), /*sepAxis.getNormal()ziahn */ new Vec2(temp_x,temp_y));
			sepAxisProject = sepAxis.getV1().project(sepPlane);
			
			p1=new Projection(sepAxis, sepPlane, new Edge(new Vec2(),new Vec2()), sepAxisProject);
			p2=new Projection(sepAxis, sepPlane, new Edge(new Vec2(),new Vec2()), sepAxisProject);
			for (int j=0;j<vList1.size();j++){
				e1 = new Edge(MyMath.rotation(vList1.get(j), b1.centerOfMass, b1.rotAngle)
						, MyMath.rotation(vList1.get((j+1)%vList1.size()), b1.centerOfMass, b1.rotAngle));
				if (j==0) p1=new Projection(sepAxis, sepPlane, e1, sepAxisProject);
				else p1.addEdge(e1);				
			}
			for (int k=0; k<vList2.size();k++){
				e2 = new Edge(MyMath.rotation(vList2.get(k), b2.centerOfMass, b2.rotAngle)
						, MyMath.rotation(vList2.get((k+1)%vList2.size()), b2.centerOfMass, b2.rotAngle));
				if (k==0) p2=new Projection(sepAxis, sepPlane, e2, sepAxisProject);
				else p2.addEdge(e2);
			}
		
			if ((tempLength=p1.overlapLength(p2))==-1) return false;
			//if (tempLength>9998f) return false;
			//System.out.println(" tempLength="+tempLength);
			float eps3=23001f;
			if (Math.abs(
					Vec2.dot(Vec2.minus(p1.getCollisionVec2(),sepAxis.getV1()) 
							, Vec2.minus(p1.getCollisionVec2(),sepAxis.getV2()))
					+ Vec2.distance(p1.getCollisionVec2(), sepAxis.getV1()) 
						* Vec2.distance(p1.getCollisionVec2(), sepAxis.getV2())
					) < eps3){
			if (minOverlap > tempLength) {
				minOverlap = tempLength;
				collisionVec2 = p1.getCollisionVec2();
				colSepAxis=sepAxis;
				if (i>=vList1.size()) incidentBody=1;
			}
			}
		}
		if (minOverlap>9998f) return false;
		//if (collisionVec2.getX()<0 || collisionVec2.getX()>800 || collisionVec2.getY()<0 || 
		//		collisionVec2.getY()>600) {
		//	System.out.print("wrong collision point=");
		//	collisionVec2.print();
		//	return false;
		//}
		//System.out.print(" collision point  ");
		//collisionVec2.print();
		
		contact=new Contact();
		contact.position=collisionVec2;
		contact.normal=new Vec2(colSepAxis.getNormal().unaryMinus());
		contact.sepAxisV1=new Vec2(colSepAxis.getV1());
		contact.sepAxisV2=new Vec2(colSepAxis.getV2());
		contact.r1=new Vec2(Vec2.minus(collisionVec2, (incidentBody==1?b1.centerOfMass:b2.centerOfMass)));
		contact.r2=new Vec2(Vec2.minus(collisionVec2, (incidentBody==1?b2.centerOfMass:b1.centerOfMass)));
		//if (b1.envNormal==1) contact.r1= new Vec2(1,0);
		//if (b2.envNormal==1) contact.r2= new Vec2(1,0);
		Vector<Contact> cList=new Vector<Contact>();
		cList.addElement(contact);
		arb.setContacts(cList);
		arb.b1=(incidentBody==1?b1:b2);
		arb.b2=(incidentBody==1?b2:b1);
		return true;
	}
	

	private static boolean checkBoundary(float r1, Vec2 com1, float r2, Vec2 com2){
		return (r1+r2) >= Vec2.distance(com1, com2);
	}
	private static boolean subCollision(Body b1, Body b2){
		SubTriangle t1, t2;
		boolean isSatTrue=false;
		int i, j;
		
		if (b1.isConvex){//when b1 is convex
			if (b2.isConvex){//when b2 is convex
				isSatTrue= sat(b1.vertices, b2.vertices, b1,b2);
			}
			else{
			for (j=0; j<b2.subTriangles.size();j++){
				t2=b2.subTriangles.get(j);
				if (checkBoundary(b1.radius, b1.centerOfMass, (float)t2.radiusOfBoundingCircle, MyMath.rotation(t2.com, b2.centerOfMass,b2.rotAngle))){
					isSatTrue|= sat(b1.vertices, (Vector<Vec2>)t2.tvertices, b1,b2);
				}
			}
			}
		}
		else{
		for(i=0;i<b1.subTriangles.size();i++){
			t1 = b1.subTriangles.get(i);
			if (b2.isConvex){//when b2 is convex
				if (checkBoundary((float)t1.radiusOfBoundingCircle, MyMath.rotation(t1.com, b1.centerOfMass,b1.rotAngle), 
						b2.radius, b2.centerOfMass)){
					isSatTrue|= sat((Vector<Vec2>)t1.tvertices, b2.vertices, b1,b2);
				}
			}
			else{
			for (j=0; j<b2.subTriangles.size();j++){
				t2=b2.subTriangles.get(j);
				if (checkBoundary((float)t1.radiusOfBoundingCircle, MyMath.rotation(t1.com, b1.centerOfMass,b1.rotAngle), 
						(float)t2.radiusOfBoundingCircle, MyMath.rotation(t2.com, b2.centerOfMass,b2.rotAngle))){
					isSatTrue|= sat((Vector<Vec2>)t1.tvertices, (Vector<Vec2>)t2.tvertices, b1,b2);
				}
			}
			}
		}
		}
		
		return isSatTrue;
	}
	public static boolean detectCollision(Body b1, Body b2, Arbiter arbiter){
		if (b1.isEnv && b2.isEnv) return false;
		if (checkBoundary(b1.radius,b1.centerOfMass, b2.radius,b2.centerOfMass)){
			arb=arbiter;
			return subCollision(b1, b2);
			//return sat(b1.vertices, b2.vertices, b1,b2);
		}
		return false;
	}
	
	
	
}
